import { BadRequestException, ConflictException, HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Like, Repository } from 'typeorm'
import { formatDate } from 'src/utils'
import { Menu } from '../menu/entities/menu.entity'
import { Permission } from '../permission/entities/permission.entity'
import { Role } from './entities/role.entity'
import { CreateRoleDto } from './dto/create-role.dto'
import { UpdateRoleDto } from './dto/update-role.dto'

@Injectable()
export class RoleService {
  private logger = new Logger()

  @InjectRepository(Role)
  private repository: Repository<Role>

  @InjectRepository(Menu)
  private menuRepository: Repository<Menu>

  @InjectRepository(Permission)
  private permissionRepository: Repository<Permission>

  async find(pageNo: number, pageSize: number, name: string) {
    // 边界条件检查
    if (pageNo <= 0 || pageSize <= 0) {
      throw new BadRequestException('页码和页数最小为 1')
    }

    const skipCount = (pageNo - 1) * pageSize
    const condition: Record<string, any> = {}
    if (name) {
      condition.name = Like(`%${name}%`)
    }

    const [roleList, totalCount] = await this.repository.findAndCount({
      skip: skipCount,
      take: pageSize,
      where: condition,
      relations: ['menu', 'permissions'],
    })

    const list = roleList.map((role) => {
      return {
        ...role,
        menu: role.menu.map(item => item.name),
        permissions: role.permissions.map(item => item.code),
        createTime: formatDate(role.createTime),
        updateTime: formatDate(role.updateTime),
      }
    })

    return {
      roleList: list,
      totalCount,
    }
  }

  async create(roleDto: CreateRoleDto) {
    // 关联菜单
    const menuList = await Promise.all(roleDto.menu.map(async (name: any) => {
      const role = await this.menuRepository.findOne({ where: { name } })
      return role
    }))

    // 关联权限
    const permisionList = await Promise.all(roleDto.permissions.map(async (name: any) => {
      const role = await this.permissionRepository.findOne({ where: { code: name } })
      return role
    }))

    try {
      // 原子性: 事务中的所有操作要么全部成功执行，要么全部不执行。如果事务中的任何一步失败，整个事务将回滚，保证数据库状态不变。
      // 隔离性: 多个事务并发执行时，每个事务的操作对其他事务是不可见的，直到事务提交。这可以防止并发操作导致的数据不一致。
      await this.repository.manager.transaction(async (transactionalEntityManager) => {
        const room = await transactionalEntityManager.findOne(Role, {
          where: { name: roleDto.name },
        })
        if (room) {
          throw new BadRequestException('角色名字已存在')
        }

        const newRole = new Role()
        newRole.name = roleDto.name
        newRole.description = roleDto.description
        newRole.menu = menuList
        newRole.permissions = permisionList

        await transactionalEntityManager.save(newRole)
      })
      return '创建成功'
    }
    catch (e) {
      if (e instanceof BadRequestException) {
        // 如果是 BadRequestException，直接抛出
        throw e
      }
      else {
        // 其他错误，记录日志并抛出通用的 HttpException
        this.logger.error(`错误信息: ${e.message}`, RoleService.name)
        throw new HttpException('创建失败，请稍后再试', HttpStatus.INTERNAL_SERVER_ERROR)
      }
    }
  }

  async update(roleDto: UpdateRoleDto) {
    if (!roleDto.id) {
      throw new BadRequestException('无效的角色 ID')
    }

    try {
      const foundRole = await this.repository.findOneBy({ id: roleDto.id })
      if (!foundRole) {
        throw new BadRequestException('角色不存在')
      }

      // 检查是否存在重复的name
      if (roleDto.name) {
        const existingRole = await this.repository.findOneBy({ name: roleDto.name })
        if (existingRole && existingRole.id !== roleDto.id) {
          throw new ConflictException('角色名称已存在')
        }
      }

      // 关联菜单
      const menuList = await Promise.all(roleDto.menu.map(async (name: any) => {
        const role = await this.menuRepository.findOne({ where: { name } })
        return role
      }))
      // 关联权限
      const permisionList = await Promise.all(roleDto.permissions.map(async (name: any) => {
        const role = await this.permissionRepository.findOne({ where: { code: name } })
        return role
      }))
      roleDto.menu = menuList
      roleDto.permissions = permisionList

      Object.assign(foundRole, roleDto)

      // 如果需要自动更新updateTime需要使用save方法，update方法不会触发更新时间
      await this.repository.save(foundRole)

      return '更新成功'
    }
    catch (e) {
      if (e instanceof BadRequestException) {
        // 如果是 BadRequestException，直接抛出
        throw e
      }
      else if (e instanceof ConflictException) {
        throw e // 直接抛出 ConflictException
      }
      else {
        // 其他错误，记录日志并抛出通用的 HttpException
        this.logger.error(`错误信息: ${e.message}`, RoleService.name)
        throw new HttpException('更新失败，请稍后再试', HttpStatus.INTERNAL_SERVER_ERROR)
      }
    }
  }

  async delete(id: number) {
    try {
      // 输入验证
      if (!id || id <= 0) {
        throw new BadRequestException('无效的id')
      }

      await this.repository.delete({ id })
      return '删除成功'
    }
    catch (e) {
      if (e instanceof BadRequestException) {
        // 如果是 BadRequestException，直接抛出
        throw e
      }
      else {
        // 其他错误，记录日志并抛出通用的 HttpException
        this.logger.error(`错误信息: ${e.message}`, RoleService.name)
        throw new HttpException('删除失败，请稍后再试', HttpStatus.INTERNAL_SERVER_ERROR)
      }
    }
  }
}
